package com.sudo.api.aspect;

import com.sudo.common.component.RedisKeys;
import com.sudo.common.ip2region.Ip2RegionStrategy;
import com.sudo.common.ip2region.IpInfo;
import com.sudo.common.utils.*;
import com.sudo.dao.admin.entity.SysUserBehavior;
import com.sudo.service.admin.service.AdminBaseService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

/**
 * @author 为道日损 2020-04-24 11:05
 */
@Order(3)
@Slf4j
@Aspect
@Component
public class DbLogAspect extends AdminBaseService {

    @Resource
    private Ip2RegionStrategy ip2RegionStrategy;

    private final static String[] excludeUriArr = {
            "/sysInfo/getCpuMemInfoActualTimeByServer",
            "/sysUser/generateImageCode",
            "/sysUser/postEmailCode",
            "/sysUser/userRegister"
    };

    /**
     * 定义切入点Pointcut
     * 在注解的位置切入代码
     */
    @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
    public void logPointCut() {}

    /**
     * 切面 配置通知
     */
    @Around("logPointCut()")
    public Object getDbLog(ProceedingJoinPoint joinPoint) throws Throwable {
        Object object;
        Thread ct = Thread.currentThread();
        //记录开始时间
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = joinPoint.getSignature().getName();
        log.info("{}-{} >>>>>>>  开始执行 {}.{}  <<<<<<<", ct.getName(),ct.getId(),className, methodName);


        HttpServletRequest request = HttpServletUtil.getRequest();
        boolean isHas = Arrays.asList(excludeUriArr).contains(request.getRequestURI());

        long begin = System.currentTimeMillis();
        object = joinPoint.proceed();
        if (isHas) {
            log.info("{}-{} -------  提前结束 {}.{}  -------",ct.getName(),ct.getId(), className, methodName);
            return object;
        }
        try {

            long end = System.currentTimeMillis();

            SysUserBehavior sysUserBehavior = new SysUserBehavior();
            //从切面织入处通过反射机制获取织入点处的方法
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();

            //获取操作
            ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
            if (null != apiOperation) {
                String value = apiOperation.value();
                sysUserBehavior.setOperEvent(value);
            }
            sysUserBehavior.setOperMethod(className + "." + methodName);

            //请求参数
            Object[] args = joinPoint.getArgs();
            Map<String, Object> nameAndArgs;
            nameAndArgs = ParamUtil.getParamMap(method, args);
            nameAndArgs.remove("request");
            nameAndArgs.remove("response");
            nameAndArgs.remove("pwd");
            nameAndArgs.remove("password");
            nameAndArgs.remove("newPassword");
            nameAndArgs.remove("oldPassword");
            nameAndArgs.remove("confirmPassword");
            nameAndArgs.remove("result");
            nameAndArgs.remove("newFileName");
            nameAndArgs.remove("timeStr");
            nameAndArgs.remove("suffix");
            //将参数所在的数组转换为json
            sysUserBehavior.setReqParam(nameAndArgs.toString());
            String now = LocalDateTimeUtil.getStandardDateTimeStr();
            sysUserBehavior.setOperTime(now);

            //获取IP
            String username = HttpUserInfoUtil.getSessionUser(request);
            if (StringUtils.isBlank(username)){
                String[] parameterNames = methodSignature.getParameterNames();
                // 获取mailOrUsername的下角标
                int usernameIndex = ArrayUtils.indexOf(parameterNames, "mailOrUsername");
                Object[] objects = joinPoint.getArgs();
                username = objects[usernameIndex].toString();
            }
            if (StringUtils.isBlank(username) && nameAndArgs.containsKey("mailOrUsername")){
                username = nameAndArgs.get("mailOrUsername").toString();
            }
            sysUserBehavior.setUsername(username);
            String roleCode = getRoleCodeFromRedisByUsername(username);
            sysUserBehavior.setRoleCode(roleCode);
            String ipAddress = IpAddressUtil.getIpAddress(request);
            String search = ip2RegionStrategy.search(ipAddress);
            IpInfo ipInfo = new IpInfo(search);

            sysUserBehavior.setClientIp(ipAddress);
            sysUserBehavior.setCountry(ipInfo.getCountry());
            sysUserBehavior.setProvince(ipInfo.getProvince());
            sysUserBehavior.setCity(ipInfo.getCity());
            sysUserBehavior.setReqUrl(request.getRequestURI());
            sysUserBehavior.setReqType(request.getMethod());
            HttpServletResponse response = HttpServletUtil.getResponse();
            sysUserBehavior.setRespStatus(response.getStatus());
            sysUserBehavior.setUseTime(end-begin);

            //sysUserBehaviorService.addSysUserBehavior(sysUserBehavior);
            stringRedisUtil.lLeftPush(RedisKeys.REDIS_USER_BEHAVIOR, JsonUtil.objectToJson(sysUserBehavior));
            log.info("{}-{} -------  结束执行 {}.{}  -------",ct.getName(),ct.getId(), className, methodName);

        }catch (Exception e){
            log.error("DbLogAspect 异常",e);
        }
        return object;
    }


}
